package net.elive.peer.p2p;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import net.elive.common.p2pnet.message.RegisterMessage;
import net.elive.common.p2pnet.message.RegisterMessageBack;
import net.elive.peer.assist.AssistServer;
import net.elive.peer.client.AssistClient;
import net.elive.peer.client.ServerClient;
import net.elive.peer.http.HttpProcessManage;
import net.elive.peer.http.HttpServer;
import net.elive.peer.rudp.ACKManage;
import net.elive.peer.rudp.DelayACKManage;
import net.elive.peer.rudp.ResendManage;
import net.elive.peer.seek.SeekServer;
import net.elive.peer.share.CacheFileManage;
import net.elive.peer.share.PublishTimer;
import net.elive.peer.share.RePublishTimer;
import net.elive.peer.share.ShareFileManage;
import net.elive.peer.share.ShareFilePathManage;
import net.elive.peer.share.SourceSessionIdManage;
import net.elive.peer.share.TempPieceGroupManage;
import net.elive.peer.utils.NetUtils;
import net.elive.tools.Contants;
import net.elive.tools.MessageCheck;
import net.elive.tools.MessageType;
import net.elive.tools.PrintByteInfo;
import net.elive.tools.RandomNum;
import net.elive.utils.LogUtils;
import net.elive.utils.VTime;

import org.apache.commons.logging.Log;

/**
 * p2p客户端加速器
 * @author Administrator
 *
 */
public class P2PAP {
	
	public static Log log = LogUtils.getLog(P2PAP.class);
	/**
	 * 常用播放器Http请求特性字符串
	 */
	public static HashSet<String> playerFeatureStr =new HashSet<String>();
	/**缓存共享**/
	public static ShareFilePathManage shareFilePathManage;		//共享文件路径名管理
	public static ShareFileManage shareFileManage;				//共享文件管理
	public static CacheFileManage cacheFileManage;				//缓存文件管理 
	public static TempPieceGroupManage tempPieceGroupManage;	//临时分片管理
	public static SourceSessionIdManage sourceSessionIdManage;	//资源ID管理
	public static PublishTimer publishTimer;					//发布计时器
	public static RePublishTimer rePublishTimer;				//重新发布计时器
	
	/** 中心服务器客户端 **/
	public static ServerClient serverClient;					//中心服务器客户端
	/**虚拟时间**/
	public static VTime vTime;
	/**搜索节点服务器**/
	public static SeekServer seekServer;						//搜索服务器 
	/**协服务器**/
	public static AssistServer assistServer;					//协服务器
	/**协服务器客户端**/
	public static AssistClient assistClient;					//协服务器客户端
	/**本地Http服务器**/
	public static HttpServer httpServer;						//本地http服务器
	public static ThreadPoolExecutor  httpThreadPool;			//http线程池
	public static HttpProcessManage httpProcessManage;			//http处理进程管理
	
	/**rudp 可靠用户数据报协议**/
	public static DelayACKManage  delayACKManage;					//rudp延时确认管理
	public static ResendManage resendMange;							//rudp重新发送管理
	public static ACKManage    ackMange;							//rudp确认管理
	/**各种线程池**/
	public static ThreadPoolExecutor transeThreadPool;			// 分片传输线程池
	public static ThreadPoolExecutor connectThreadPool;			// rudp连接初始化线程池
	public static ThreadPoolExecutor tunnelCloseThreadPool;		// 隧道关闭线程池
	public static ThreadPoolExecutor connectProcessorThreadPool;// rudp连接处理线程池
	public static ThreadPoolExecutor tunnelProcessorThreadPool;	// rudp隧道处理线程池
	
	public static HashMap threadCountMap = new HashMap();		//统计程序的线程数
	/*******************************初始化本机环境开始*********************************/
	/**
	 * 初始化本地环境
	 */
	public static void initLocal(){
		/**
		 * 初始化常用播放器Http请求特性字符串
		 */
		initPlayerFeature();
		/**
		 * 初始化各种线程池
		 */
		initThreadPool();
		/**
		 * 初始化路由端口
		 */
		initRoutePort();
		/**
		 * 初始化各种目录
		 */
		initDirectory();
		/**
		 * 初始化各种服务
		 */
		initServer();
	}
	/**
	 * 初始化常用播放器Http请求特性字符串
	 */
	public static void initPlayerFeature(){
		playerFeatureStr.add("User-Agent: MPlayer");
		playerFeatureStr.add("User-Agent: RMA");
		playerFeatureStr.add("User-Agent: Windows-Media-Player");
	}
	
	/**
	 * 初始化各种线程池
	 */
	public static void initThreadPool(){
		// rudp连接初始化线程池
		ArrayBlockingQueue<Runnable> abq1 = new ArrayBlockingQueue<Runnable>(500);
		connectThreadPool = new ThreadPoolExecutor(10, 100, 5,TimeUnit.SECONDS, abq1);
		// rudp连接处理线程池
		ArrayBlockingQueue<Runnable> abq2 = new ArrayBlockingQueue<Runnable>(500);
		connectProcessorThreadPool = new ThreadPoolExecutor(10, 100, 5,TimeUnit.SECONDS, abq2);
		// 隧道关闭线程池
		ArrayBlockingQueue<Runnable> abq8 = new ArrayBlockingQueue<Runnable>(500);
		tunnelCloseThreadPool = new ThreadPoolExecutor(10, 100, 5,TimeUnit.SECONDS, abq8);
		// rudp隧道处理线程池
		ArrayBlockingQueue<Runnable> abq5 = new ArrayBlockingQueue<Runnable>(500);
		tunnelProcessorThreadPool = new ThreadPoolExecutor(10, 100, 5,TimeUnit.SECONDS, abq5);
		// 分片传输线程池
		ArrayBlockingQueue<Runnable> abq3 = new ArrayBlockingQueue<Runnable>(500);
		transeThreadPool = new ThreadPoolExecutor(10, 100, 5, TimeUnit.SECONDS,abq3);
		//http线程池
		ArrayBlockingQueue<Runnable> abq4 = new ArrayBlockingQueue<Runnable>(500);
		httpThreadPool = new ThreadPoolExecutor(10, 100, 5, TimeUnit.SECONDS,abq4);
		//统计各种线程池数量
		new Thread() {
			public void run() {
				while (true) {
					System.out.println("ThreadPoolThreadPool "
							+ connectThreadPool.getActiveCount() + " "
							+ connectProcessorThreadPool.getActiveCount() + " "
							+ tunnelCloseThreadPool.getActiveCount() + " "
							+ tunnelProcessorThreadPool.getActiveCount() + " "
							+ transeThreadPool.getActiveCount() + " "
							+ httpThreadPool.getActiveCount());

					Iterator it = threadCountMap.keySet().iterator();
					while (it.hasNext()) {
						String str = (String) it.next();
						ThreadCount tc = (ThreadCount) threadCountMap
								.get(str);
						if (tc.count > 0) {
							System.out.println("TSTR " + tc.count + " " + str);
							if (str.equals("56jnjrtuy65")) {
								System.out.println("MAX56jnjrtuy65 " + tc.count
										+ " " + tc.max);
							}
						}
					}

					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};//.start();
	}
	/**
	 * 初始化路由端口
	 * @param args
	 */
	public static void initRoutePort(){
		// 选择一个可用的route端口
		while (true) {
			Contants.ROUTE_PORT = RandomNum.randomInt(65505);
			DatagramSocket ds = null;
			try {
				ds = new DatagramSocket(Contants.ROUTE_PORT);
			} catch (SocketException e) {
				e.printStackTrace();
				continue;
			} finally {
				ds.close();
			}
			break;
		}
		log.info(">>>>>>>随机产生一个路由端口:"+Contants.ROUTE_PORT );
	}
	/**
	 * 初始化各种目录
	 */
	public static void initDirectory(){
		/**
		 * 
		 */
	}
	/**
	 * 启动各种服务
	 */
	public static void initServer(){
		sourceSessionIdManage = new SourceSessionIdManage();	//资源ID管理
		shareFileManage  = new ShareFileManage();				//共享文件管理
		shareFilePathManage = new ShareFilePathManage();		//共享文件路径管理
		cacheFileManage =new CacheFileManage();					//缓存文件管理 
		tempPieceGroupManage = new TempPieceGroupManage();		//临时分片管理
		delayACKManage = new DelayACKManage();					//rudp延时确认管理
		resendMange = new ResendManage();						//rudp重发管理
		ackMange = new ACKManage();								//rudp确认管理
		seekServer= new SeekServer();							//搜索服务器
		assistServer = new AssistServer();						//协服务器
		httpServer = new HttpServer();							//http服务器
		publishTimer =new PublishTimer();						//发布计时器
		rePublishTimer = new RePublishTimer();					//启动重新发布计时器
	}
	/*******************************初始化本机环境结束*********************************/
	
	/*******************************初始化网络环境开始*********************************/
	/**
	 * 初始化网络环境
	 */
	public static void initNet(){
		NetUtils.setCIP();			//设置中心服务器IP
		NetUtils.setLanIp();		//设置局域网IP
		loginCenterServer();		//登录中心服务器
		
	}
	/**登录中心服务器**/
	public static void loginCenterServer(){
		DatagramSocket ds = null;
		log.info(">>>>>>>>>正在登录中心服务器>>>>>>>");
		try {
			ds = new DatagramSocket();
			ds.setSoTimeout(Contants.C_SO_TIMEOUT);		
		} catch (SocketException e) {
			e.printStackTrace();
		}
		RegisterMessage regMessage = new RegisterMessage();
		log.info("发送注册信息数据报信息"+regMessage.getDatagramPacket().getData());
		regMessage.setDestnationAddress(Contants.C_IP);
		regMessage.setDestnationPort(Contants.C_PORT);
		
		/**
		 * 若不在线,重新登录
		 */
		int loginTimes=0;
		while(!Contants.C_IS_LIVE){
				loginTimes++;
				log.info(">>>>>>>>>>>>尝试第"+loginTimes+"次登录中>>>>>>>>>>>>>");
				try {
					/**
					 * 发送注册信息数据报
					 */
					ds.send(regMessage.getDatagramPacket());
					log.info("发送注册信息数据报信息"+regMessage.getDatagramPacket().getData());
				} catch (IOException e) {
					log.info(">>>>>>>>>>>>>>>>>发送注册信息数据报失败,重新发送>>>>>>>>>");
					e.printStackTrace();
				}	
				byte[] data = new byte[1024];
				DatagramPacket dataPacket = new DatagramPacket(data,data.length);
				try {
					ds.receive(dataPacket);
					log.info(">>>>>>>>>>>>>>>>>接受数据报>>>>"+dataPacket.getData()+"版本号:"+MessageCheck.checkVersion(dataPacket)+"消息类型："+MessageCheck.checkSType(dataPacket));
				} catch (IOException e) {
					log.info(">>>>>>>>>>>>>>>>登录超时!!重新登录>>>>>>>>>>>>>>>>>>");
					e.printStackTrace();
					continue;
				}
				/**
				 * 若协议版本号,消息类型为注册消息类型,登录成功
				 */
				if(MessageCheck.checkVersion(dataPacket)==Contants.VERSION);{
					if(MessageCheck.checkSType(dataPacket) == MessageType.STYPE_REGMESSAGE_BACK){
						log.info(">>>>>>>>>>>>>>>>>>正在检查注册协议版本和消息类型>>>>>>>>>>>");
						/**
						 * 注册返回信息
						 */
						RegisterMessageBack regMessageBack =new RegisterMessageBack(dataPacket);
						/**登录session**/
						int sessionId = regMessageBack.getSessionId();
						Contants.SESSION_ID = sessionId;
						ds.close();						//关闭连接
						Contants.C_IS_LIVE = true;		//在线
						/**
						 * 登录成功,启动客户端并同步虚拟时间
						 */
						serverClient = new ServerClient();
						log.info(">>>>>>>>>>>>>>登录成功,服务器Session:"+Contants.SESSION_ID);
						break;
					}
				}
				
		}
	}
	/*******************************初始化网络环境结束*********************************/
	/**
	 * 获取服务器时间
	 */
	public static long getVTime(){
		if(vTime != null){
			return vTime.getCurrentTime();
		}else{
			return System.currentTimeMillis();
		}
	}
	
	/**
	 * 主函数
	 * @param args
	 */
	public static void main(String []args){
		P2PAP.initLocal();
		P2PAP.initNet();
	}
}
